package com.exam.api.common.utils.geo;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;

/**
 * 距离计算工具类
 *
 * @author bcheng
 */
public final class GeoUtil {

    // 地球平均半径，单位为公里
    public static final double EARTH_RADIUS_KM = 6371.01;

    /**
     * 根据坐标计算距离
     *
     * @param lat1 第一个点的纬度
     * @param lon1 第一个点的经度
     * @param lat2 第二个点的纬度
     * @param lon2 第二个点的经度
     * @param unit 距离单位（米、公里、英里、英尺）
     * @return 两点之间的距离，单位为指定的单位
     * @throws IllegalArgumentException 如果单位为null或坐标无效
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2, GeoUnit unit) {
        Objects.requireNonNull(unit, "距离单位不能为空");

        // 验证纬度和经度是否在有效范围内
        if (lat1 < -90 || lat1 > 90 || lat2 < -90 || lat2 > 90 ||
                lon1 < -180 || lon1 > 180 || lon2 < -180 || lon2 > 180) {
            throw new IllegalArgumentException("纬度必须在 [-90， 90] 范围内，经度必须在 [-180， 180] 范围内");
        }

        // 将经纬度差转换为弧度
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);

        // 计算哈弗公式中的a值
        double a = Math.pow(Math.sin(dLat / 2), 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.pow(Math.sin(dLon / 2), 2);

        // 计算哈弗公式中的c值
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        double distance = (EARTH_RADIUS_KM * c) * unit.getFactor();
        // 计算两点之间的距离
        return BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }

    public static void main(String[] args) {

        // 测试点1: 光合空间
        double lat1 = 39.906848; // 纬度
        double lon1 = 116.610816; // 经度

        // 测试点2: 阳光100
        double lat2 = 39.918712; // 纬度
        double lon2 = 116.481546; // 经度

        // 使用GeoUnit.KILOMETERS计算两个点之间的距离
        double distanceKm = GeoUtil.calculateDistance(lat1, lon1, lat2, lon2, GeoUnit.KILOMETERS);

        System.out.println(distanceKm);
    }
}
